using System;
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
using BuffSystem;

public class BuffManager : MonoBehaviour
{
    private MainFrame _mainFrame;

    public event Action ON_BuffUpdate = delegate { };
    public event Action ON_PropertyUpdate = delegate { };
    public event Action ON_TagUpdate = delegate { };

    private Dictionary<string, PropertyModifier> _modifier_Registry = new Dictionary<string, PropertyModifier>();
    public PropertyModifier _sumModifier = new PropertyModifier();

    private Dictionary<string, TagSystem> _tag_Registry = new Dictionary<string, TagSystem>();

    private Dictionary<string, Action> _buffUnregister_Registry = new Dictionary<string, Action>();
    private Dictionary<string, Action> _trigger_Registry = new Dictionary<string, Action>();

    private void Awake()
    {
        _mainFrame = GetComponent<MainFrame>();
        ON_PropertyUpdate += RefreshPropertyModifier;
    }

    private void Update()
    {
        //register a test buff
        if (Input.GetKeyDown(KeyCode.X))
        {
            if (gameObject.name == "Cruiser")
            {
                AssetsManager.AssetsManagerInstance.DeserializeBuff(BuffName.TestBuff).RegisterBuff(this, this);
            }
        }
        if (Input.GetKeyDown(KeyCode.C))
        {
            if (gameObject.name == "Cruiser_1")
            {
                AssetsManager.AssetsManagerInstance.DeserializeBuff(BuffName.TestBuff).RegisterBuff(this, this);
            }
            if (gameObject.name == "Cruiser")
            {
                AssetsManager.AssetsManagerInstance.DeserializeBuff(BuffName.SlowDown).RegisterBuff(this, this);
            }
        }
    }

    public void Register(string key, Buff buff)
    {
        if (!_buffUnregister_Registry.ContainsKey(key))//todo: stack
        {
            _buffUnregister_Registry.Add(key, buff.UnregisterBuff);//no buff object, so there is a unregister event
            ON_BuffUpdate();
        }
    }

    public void Register(string key, PropertyModifier propertyModifier)
    {
        if (!_modifier_Registry.ContainsKey(key))
        {
            _modifier_Registry.Add(key, propertyModifier);
            ON_PropertyUpdate();
        }
    }
    public void Register(string key, TagSystem tagSystem)
    {
        if (!_tag_Registry.ContainsKey(key))
        {
            _tag_Registry.Add(key, tagSystem);
            //todo: a behavior
            ON_TagUpdate();
        }
    }

    public void Unregister(string key, OccupantType occupantType)
    {
        switch (occupantType)
        {
            case OccupantType.Buff:
                if (_buffUnregister_Registry.ContainsKey(key))
                {
                    _buffUnregister_Registry[key]();//unregister buff component
                    _buffUnregister_Registry.Remove(key);
                    ON_BuffUpdate();
                }
                break;
            case OccupantType.PropertyModifier:
                if (_modifier_Registry.ContainsKey(key))
                {
                    _modifier_Registry.Remove(key);
                    ON_PropertyUpdate();
                }
                break;
            case OccupantType.Tag://todo: unregister the tag event
                if (_tag_Registry.ContainsKey(key))
                {

                    _tag_Registry.Remove(key);
                    ON_TagUpdate();
                }
                break;
            default:
                break;
        }
    }

    public bool CheckTag(TagSystem tagObject)
    {
        foreach (TagSystem tag in _tag_Registry.Values)
        {
            if (tag._isActive && tag._buffTag == tagObject._buffTag)
            {
                return true;
            }
        }
        return false;
    }
    private void TagEvent()
    {
        //sort tag.level
        //ON_TagUpdate += tag(match the level).event
    }

    private void RefreshPropertyModifier()
    {
        _sumModifier = new PropertyModifier();
        foreach (PropertyModifier modifier in _modifier_Registry.Values.OfType<PropertyModifier>().ToList())
        {
            _sumModifier = modifier._isActive ? _sumModifier + modifier : _sumModifier;
        }
        //todo: update when set property inactive or active
    }
    public void RegisterTrigger(string occupantKey, TriggerType triggerType, Action action)
    {
        if (!_trigger_Registry.ContainsKey(occupantKey))
        {
            _trigger_Registry.Add(occupantKey, action);
            switch (triggerType)
            {
                case TriggerType.ON_Idle:
                    _mainFrame.ON_Idle = (Action)Delegate.Combine(_mainFrame.ON_Idle, action);
                    break;
                case TriggerType.ON_Move:
                    _mainFrame.ON_Move = (Action)Delegate.Combine(_mainFrame.ON_Move, action);
                    break;
                case TriggerType.ON_Attack:
                    _mainFrame.ON_Attack = (Action)Delegate.Combine(_mainFrame.ON_Attack, action);
                    break;
                case TriggerType.ON_Hit:
                    _mainFrame.ON_Hit = (Action)Delegate.Combine(_mainFrame.ON_Hit, action);
                    break;
                case TriggerType.ON_Death:
                    _mainFrame.ON_Death = (Action)Delegate.Combine(_mainFrame.ON_Death, action);
                    break;
                case TriggerType.ON_PerformSkill:
                    _mainFrame.ON_PerformSkill = (Action)Delegate.Combine(_mainFrame.ON_PerformSkill, action);
                    break;
                default:
                    break;
            }
        }
    }
    public void UnregisterTrigger(string key, TriggerType triggerType)
    {
        if (_trigger_Registry.ContainsKey(key))
        {
            switch (triggerType)
            {
                case TriggerType.ON_Idle:
                    _mainFrame.ON_Idle = (Action)Delegate.Remove(_mainFrame.ON_Idle, _trigger_Registry[key]);
                    break;
                case TriggerType.ON_Move:
                    _mainFrame.ON_Move = (Action)Delegate.Combine(_mainFrame.ON_Move, _trigger_Registry[key]);
                    break;
                case TriggerType.ON_Attack:
                    _mainFrame.ON_Attack = (Action)Delegate.Combine(_mainFrame.ON_Attack, _trigger_Registry[key]);
                    break;
                case TriggerType.ON_Hit:
                    _mainFrame.ON_Hit = (Action)Delegate.Combine(_mainFrame.ON_Hit, _trigger_Registry[key]);
                    break;
                case TriggerType.ON_Death:
                    _mainFrame.ON_Death = (Action)Delegate.Combine(_mainFrame.ON_Death, _trigger_Registry[key]);
                    break;
                case TriggerType.ON_PerformSkill:
                    _mainFrame.ON_PerformSkill = (Action)Delegate.Combine(_mainFrame.ON_PerformSkill, _trigger_Registry[key]);
                    break;
                default:
                    break;
            }
            _trigger_Registry.Remove(key);
        }
    }
}
